// 单波段数据最大合成

#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include "wstringutils.h"
#include "wGdalRaster.h"
#define WGDALRASTER_H_IMPLEMENTATION
#include "wGdalRaster.h"
#include <iostream>
#include "gdal_priv.h"
#include "ogr_spatialref.h"
#include <memory>
#include "getopt_pp.h"
#include "wdirtools.h"

using namespace std;
using namespace GetOpt;


bool ReadFileList(string listfilename ,vector<string>& filenameVec)
{
	std::ifstream infs(listfilename.c_str());
	if( infs.good()==false ) return false ;
	std::string line;
	while (std::getline(infs, line))
	{
		if( line.length() > 2 )
		{
			filenameVec.push_back( line ) ;
		}
	}
	return true ;
}


bool FillOneFileIntoOutput( 
	wGdalRaster* outRas0 ,
	string oneInputFile ,
	double vmin ,
	double vmax , 
	double fillvalue ,
	string& error
	)
{
	cout<<"begin for "<<oneInputFile<<endl ;
	shared_ptr<wGdalRaster> inRas(wGdalRasterFactory::OpenFile( oneInputFile )) ;

	if( inRas.get() == 0 ){
		error = oneInputFile + " is bad";
		return false ;
	}
	
	const int inxsize = inRas->getXSize() ;
	const int inysize = inRas->getYSize() ;
	const int outxsize = outRas0->getXSize() ;
	const int outysize = outRas0->getYSize() ;

	if( inxsize!= outxsize || inysize != outysize )
	{
		error = oneInputFile + " have different size." ;
		return false ;
	} 
	int per0 =  -1;
	for(int oy = 0 ; oy < outysize ; ++ oy )
	{
		for(int ox =0 ; ox < outxsize ; ++ ox )
		{
			double inval = inRas->getValued(ox,oy,0) ;
			if( inval >= vmin && inval <= vmax )
			{
				if( inval > outRas0->getValued(ox,oy,0) ){
					outRas0->setValued(ox,oy,0,inval) ;
				}
			}	
		}
		int per1 =  oy * 100.0 / outysize  ;
		if( per1%10==0 && per1 != per0 ){
			per0 = per1 ;
			cout<<per0<<endl ;
		}
	}
	cout<<"100 "<<endl ;
	return true ;
}


int main(int argc , char** argv )
{
	cout<<"A program to do max composite for one band data."<<endl ;
	cout<<  "v2.0.2 2023-12-27 add filename template"<<endl ;
	cout<<"usage1.x:qh5_maxdatacomposite infilelist.txt vmin vmax fillval output.tif"<<endl ;
	cout<<"usage2.x:qh5_maxdatacomposite -p prefix -t tail -d /some/dir --min vmin --max vmax -f fillval -o output.tif"<<endl ;
	cout<<"for 1.x:"<<endl;
	cout<<"infilelist.txt: one line has one file path."<<endl ;
	cout<<"e.g.:"<<endl ;
	cout<<"/some/ndvidir/ndvi1.tif"<<endl ;
	cout<<"/some/ndvidir/ndvi2.tif"<<endl ;
	cout<<"/some/ndvidir/ndvi3.tif"<<endl ;

	GDALAllRegister() ;
	bool useV1 = false;
	string infilelist ;
	double vmin(0),vmax(0),fillval(0) ;
	string outfile ;
	vector<string> infileVec ;
	string prefix,tail,indir ;
	if( argc==6 )
	{	
		cout<<"using 1.x mode"<<endl;
		useV1 = true ;
		infilelist = argv[1] ;
	    vmin = atof(argv[2]) ;
	    vmax = atof(argv[3]) ;
	    fillval = atof(argv[4]) ;
	    outfile = argv[5] ;
	    cout<<"------------"<<endl ;
		cout<<"infilelist :"<<infilelist<<endl ;
		cout<<"vmin :"<<vmin<<endl ;
		cout<<"vmax :"<<vmax<<endl ;
		cout<<"fillval :"<<fillval<<endl ;
		cout<<"outfile :"<<outfile<<endl ;
		cout<<"------------"<<endl ;

		bool listok = ReadFileList( infilelist , infileVec ) ;
		if( listok==false ){
			cout<<"failed to read infilelist:"<<infilelist<<endl ;
			return 12 ;
		}

	}else{
		cout<<"using 2.x mode"<<endl;
		useV1 = false ;
		GetOpt_pp ops(argc,argv);
		ops>>Option('p',prefix);
		ops>>Option('t',tail) ;
		ops>>Option('d',indir);
		ops>>Option('f',fillval);
		ops>>Option('o',outfile) ;
		ops>>Option("min",vmin) ;
		ops>>Option("max",vmax) ;
		cout<<"------------"<<endl ;
		cout<<"prefix :"<<prefix<<endl ;
		cout<<"tail :"<<tail<<endl ;
		cout<<"indir :"<<indir<<endl ;
		cout<<"vmin :"<<vmin<<endl ;
		cout<<"vmax :"<<vmax<<endl ;
		cout<<"fillval :"<<fillval<<endl ;
		cout<<"outfile :"<<outfile<<endl ;
		cout<<"------------"<<endl ;
		if( prefix=="" || tail=="" || indir=="" || outfile=="") {
			cout<<"some of prefix, tail, indir, outfile is empty."<<endl;
			return 11 ;
		}

		wDirTools wdir;
		bool isok = wdir.getDirFiles(
			indir ,prefix, tail, infileVec) ;
		if( isok==false ){
			cout<<"failed to get files in dir "<<indir<<endl;
			return 13 ;
		}
		//write down file list
		string outfilelist = outfile+".flist.txt" ;
		cout<<"writing "<<outfilelist<<endl;
		ofstream ofs(outfilelist.c_str()) ;
		for(int ii = 0 ; ii<infileVec.size();++ii ) ofs<<infileVec[ii]<<endl;
		ofs.close();
	}


	if( infileVec.size()==0 ){
		cout<<"infileVec size equal 0. "<<endl ;
		return 13 ;
	}

	char projbuff[2048] ;
	double trans[6] ;


	// only one band ok.int theBandNum = 0 ;
	{
		shared_ptr<wGdalRaster> tempPtr(wGdalRasterFactory::OpenFile( infileVec[0] )) ;
		if( tempPtr.get() == 0 ){
			cout<<"bad ndvifile 0."<<endl ;
			return 14 ;
		}
		
		GDALDataType thedatatype = tempPtr->getDataType() ;

		shared_ptr<wGdalRaster> outRas0( wGdalRasterFactory::Create( 
			tempPtr->getXSize() ,
			tempPtr->getYSize() ,
			1,
			thedatatype) 
		) ;

		if( outRas0.get() == 0 )
		{
			cout<<"create outRas0 failed."<<endl ;
			return false ;
		}

		outRas0->copyProj( tempPtr->getProj() ) ;
		outRas0->copyTrans( tempPtr->getTrans() ) ;

		outRas0->fill(0, fillval) ;
		for(int iin = 0 ; iin < infileVec.size() ; ++ iin )
		{
			cout<<"ifile "<<iin<<"/"<<infileVec.size()<<endl ;
			string error1;

			bool ok1 = FillOneFileIntoOutput(outRas0.get(),
				infileVec[iin],
				vmin,
				vmax,
				fillval,
				error1) ;
			if( ok1==false ){
				cout<<"bad FillOneFileIntoOutput run:"<<error1<<endl ;
				return 16 ;
			}
		}

		cout<<"saving..."<<endl ;
		bool saveok1 = outRas0->save(outfile,fillval,true) ;
		if( saveok1==false ){
			cout<<"failed to save "<<outfile<<endl ;
			return 17 ;
		}

	}	

	cout<<"success"<<endl ;

	return 0 ;
}
